package main

import (
	"flag"
	"fmt"
	"gitee.com/liumou_site/gf"
	"os"
	"runtime"
	"sync"
	"time"

	"gitee.com/liumou_site/gbm"
	"gitee.com/liumou_site/gns"
	"gitee.com/liumou_site/logger"
	"github.com/spf13/cast"
)

var wg sync.WaitGroup // 定义一个计数器
var wl sync.RWMutex   // 定义一个读写锁

var (
	start      int      // 开始值
	stop       int      // 结束值
	sub        string   // 子网
	successTxt []string //成功记录
	successInt []int    // 成功记录Index数组
	failedTxt  []string // 失败记录
	failedInt  []int    // 失败记录Index数组
	failed     bool     // 显示失败
	success    bool     // 是否显示成功列表
	w          bool     // 是否写入记录结果到文本文件
	debug      bool     // 是否显示检测日志详细信息
	n          bool     // 使用命令模式
)

// // 开始Ping
// func ping(host string) {
// 	err := gns.Ping(host, 3, debug)
// 	wl.Lock()
// 	defer wl.Unlock()
// 	if err != nil {
// 		if debug {
// 			logger.Error("失败: ", host)
// 		}
// 		failedTxt = append(failedTxt, host)
// 	} else {
// 		if debug {
// 			logger.Info("成功: ", host)
// 		}
// 		successTxt = append(successTxt, host)
// 	}
// 	wg.Done() // 完成一个计时器
// }

// pings 使用系统命令进行检测
func pings(host string) {
	var err error                       // 错误信息
	var IpIndex int                     // IP最后一位数
	IpIndex, err = gns.IpCutEndId(host) // 获取此IP最后一位数
	if err != nil {
		logger.Error(err.Error())
	}
	OsType := runtime.GOOS
	if OsType == "windows" {
		err = gns.Ping(host, 5, false)
	} else {
		p := gns.NewPing(5, 5)
		p.Realtime = false
		err = p.PingCmd(host)
	}
	wl.Lock()
	defer wl.Unlock()
	if err != nil {
		if debug {
			logger.Error(err.Error())
			logger.Error("失败: ", host)
		}
		//failedTxt = append(failedTxt, host)
		failedInt = append(failedInt, IpIndex)
	} else {
		if debug {
			logger.Info("成功: ", host)
		}
		//successTxt = append(successTxt, host)
		successInt = append(successInt, IpIndex)
	}
	wg.Done() // 完成一个计时器

}

// 写入结果到文件
func write(txt, file string) error {
	if txt != "" {
		wf := gf.NewFile(file)
		wf.EchoAdd(txt, true)
		return wf.Err
	}
	return fmt.Errorf("无内容")
}

func main() {
	var DemoIp string
	defaultSub := "192.168.1"
	ip := gns.NewIp()
	useIp, err := ip.GetUseIP()
	if err == nil {
		defaultSub = gns.IpCutSubnet(useIp)
	}
	fg := flag.NewFlagSet("pings v1.3.0", flag.ExitOnError)
	fg.StringVar(&sub, "ns", defaultSub, "设置IP网段")
	fg.IntVar(&start, "start", 1, "设置开始IP: 0-255")
	fg.IntVar(&stop, "stop", 254, "设置结束IP: 1-255")
	fg.BoolVar(&failed, "f", false, "显示失败的IP列表")
	fg.BoolVar(&success, "s", false, "显示成功的IP列表")
	fg.BoolVar(&w, "w", true, "写入结果到文件")
	fg.BoolVar(&debug, "d", false, "显示检测过程日志")
	fg.BoolVar(&n, "n", false, "设置每个IP显示一行")
	args := os.Args
	err = fg.Parse(args[1:])
	if err != nil {
		return
	}
	if start >= stop {
		logger.Error("开始值大于或等于结束值")
		os.Exit(1)
	}
	if start < 0 || start > 255 {
		logger.Error("开始值小于0/大于255")
		os.Exit(2)
	}
	if stop < 0 || stop > 255 {
		logger.Error("结束值小于0/大于255")
		os.Exit(3)
	}
	start_ := cast.ToUint8(start)
	stop_ := cast.ToUint8(stop)
	StartTime := time.Now()
	IpSub, errors := gns.IpGenerateList(sub, start_, stop_) // 生成100个IP(切片)
	if errors == nil {
		wg.Add(len(IpSub))
		for _, DemoIp = range IpSub {
			go pings(DemoIp)
		}
		wg.Wait() // 等待所有任务完成
	} else {
		logger.Error("IP生成异常: ", errors.Error())
		os.Exit(4)
	}
	UseTime := time.Since(StartTime)
	successTxt, err = gns.IpGenerateIndex(DemoIp, successInt)
	if err != nil {
		logger.Error("Ip排序出错")
		return
	}
	failedTxt, err = gns.IpGenerateIndex(DemoIp, failedInt)
	if err != nil {
		logger.Error("Ip排序出错")
		return
	}
	if success {
		fmt.Println("连接成功的列表如下: ")
		if n {
			fmt.Println(gbm.SliceToString(successTxt, "\n"))
		} else {
			fmt.Println(successTxt)
		}
	}
	if failed {
		fmt.Println("连接失败的列表如下: ")
		if n {
			fmt.Println(gbm.SliceToString(failedTxt, "\n"))
		} else {
			fmt.Println(failedTxt)
		}
	}
	if w {
		_ = write(gbm.SliceToString(successTxt, "\n"), "success.txt")
		_ = write(gbm.SliceToString(failedTxt, "\n"), "failed.txt")
		fmt.Println("结果已保存到文件: ")
		fmt.Println("success.txt")
		fmt.Println("failed.txt")
	}
	logger.Info("成功数量: ", len(successTxt))
	logger.Info("失败数量: ", len(failedTxt))
	logger.Info("耗时: ", UseTime)
}
